﻿/*
设计：
1. 使用int表示结果，每个表示8位，因为long最多可以表示19位（20位不够）
2. 索引0表示低位，索引值越大，位数越高

3000!约160ms

*/

using ConsoleAlgorithms;
using System;
using System.Collections.Generic;
using System.Text;

namespace HelloWorld.Utils
{
    public class BigNumber1 : ITestable
    {
        public void Test()
        {
            BigNumber1 b1 = new BigNumber1(12345678);
            BigNumber1 b2 = new BigNumber1(300);
            BigNumber1 b3 = b1 * b2;
            BigNumber1 b4 = b3 * b3;

            //Console.WriteLine("b1: " + b1);
            //Console.WriteLine("b2: " + b2);
            //Console.WriteLine("b3: " + b3);
            //Console.WriteLine("b4: " + b4);


            for (int i = 0; i < 10; i++)
            {
                OneTest();
            }
        }

        static void OneTest()
        {
            DateTime t1 = DateTime.Now;
            BigNumber1 b = new BigNumber1(1);
            for (int i = 1; i <= 6000; i++)
            {
                BigNumber1 bi = new BigNumber1(i);
                b = b * bi;
            }
            DateTime t2 = DateTime.Now;


            var time = (t2 - t1).TotalMilliseconds;
            Console.WriteLine($"BigNumber 1: Time: {time:0.0}ms, b.length:{b.ToString().Length}");
        }



        public List<long> Data = new List<long>();
        public int Sign = 1;

        static int numerator = 1_0000_0000;

        public BigNumber1() { }
        public BigNumber1(long v)
        {
            long v0 = v;
            Data.Clear();
            while (v0 > 0)
            {
                Data.Add(v0 % numerator);
                v0 = v0 / numerator;
            }

            // 123 -> {3,2,1}, bts[0] = 3, bts[1] = 2, bts[2] = 3
        }


        /// <summary>
        /// 读取或设置指定的索引的值。
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public long this[int index]
        {
            get { return Data[index]; }
            set { Data[index] = value; }
        }



        public static BigNumber1 operator +(BigNumber1 b1, BigNumber1 b2)
        {
            BigNumber1 b3 = b1.Clone();

            while (b3.Length < b2.Length)
                b3.Data.Add(0);

            for (int i = 0; i < b2.Length; i++)
                b3[i] += b2[i];

            b3.normalize();

            return b3;
        }

        public static BigNumber1 operator *(BigNumber1 b1, BigNumber1 b2)
        {
            BigNumber1 b3 = new BigNumber1();
            for (int i = 0; i < b1.Length + b2.Length + 1; i++)
                b3.Data.Add(0);

            for (int i = 0; i < b2.Length; i++)
            {
                for (int j = 0; j < b1.Length; j++)
                {
                    b3[j + i] += b1[j] * b2[i];
                }
                b3.normalize(false);
            }
            b3.normalize();
            return b3;
        }

        public BigNumber1 Clone()
        {
            var b = new BigNumber1();
            for (int i = 0; i < Data.Count; i++)
                b.Data.Add(Data[i]);
            return b;
        }

        /// <summary>
        /// 数据长度。
        /// </summary>
        public int Length { get => Data.Count; }


        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < Length; i++)
            {
                // if (i > 0 && i % 3 == 0) sb.Insert(0, ',');
                sb.Insert(0, i == Length - 1 ? this[i] : $"{this[i]:00000000}");
            }
            if (Sign < 0)
                sb.Insert(0, '-');

            return sb.ToString();
        }

        void normalize(bool removeZeros = true)
        {
            Data.Add(0);
            for (int i = 0; i < Data.Count - 1; i++)
            {
                Data[i + 1] += Data[i] / numerator;
                Data[i] = Data[i] % numerator;
            }

            while (removeZeros && Data.Count > 0 && Data[Data.Count - 1] == 0)
                Data.RemoveAt(Data.Count - 1);
        }



    }
}
